#include <string.h>
#ifdef WIN32
#include <winsock2.h>


#else

#include <arpa/inet.h>

#ifndef ntohll
#define ntohll(x) ((uint64_t)ntohl((uint32_t)((x) << 32)) | \
                   (uint64_t)ntohl((uint32_t)((x) & 0xffffffff)))
#endif
#endif
#include "ParseH264.h"




static int FindStartCode2(unsigned char* Buf);//查找开始字符0x000001
static int FindStartCode3(unsigned char* Buf);//查找开始字符0x00000001


static int FindStartCode2(unsigned char* Buf)
{
	if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 1)
		return 0; //判断是否为0x000001,如果是返回1
	else
		return 1;
}

static int FindStartCode3(unsigned char* Buf)
{
	if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 0 || Buf[3] != 1)
		return 0;//判断是否为0x00000001,如果是返回1
	else
		return 1;
}


ParseH264::ParseH264()
{


}

ParseH264::~ParseH264()
{
	Uinit();
}


int ParseH264::Init(char* path)
{

	bits = fopen(path, "rb");
	if(bits == NULL)
	{
		printf("open file error\n");
		exit(0);
	}

	m_nalu.max_size = 1920 * 1080 * 3;
	if (m_nalu.buf == NULL) {

		m_nalu.buf = new char[m_nalu.max_size];
	}
	if (Buf == NULL) {

		Buf = new unsigned char[m_nalu.max_size];
	}


	return 0;
}

void ParseH264::Uinit()
{
	if (bits)
	{
		fclose(bits);
		bits = 0;
	}
	if (Buf)
	{
		delete[] Buf;
		Buf = 0;
	}



	if (m_nalu.buf)
	{
		delete[] m_nalu.buf;
		m_nalu.buf = 0;
	}

}
int ParseH264::Reset()
{
	fseek(bits, 0, SEEK_SET);
	return 0;
}
int ParseH264::GetAnnexbNALU(NALU_t *& nalu, int flags)
{


	m_nalu.nal_unit_type = 0;
	nalu = &m_nalu;
	if (feof(bits))
	{
		return -11;
	}

	if (flags == 2)
	{
		if (4 != fread(Buf, 1, 4, bits))
		{
			return 0;
		}
		if (0x11 == Buf[0] && 0x22 == Buf[1] && 0x33 == Buf[2] && 0x44 == Buf[3])
		{
			m_nalu.bFrameType = 0;
		}
		else if (0x22 == Buf[0] && 0x33 == Buf[1] && 0x44 == Buf[2] && 0x55 == Buf[3])
		{
			m_nalu.bFrameType = 1;
		}
		else
		{
			m_nalu.bFrameType = -1;
		}

		int t_len = 0;
		if (1 != fread(&t_len, 4, 1, bits))
		{
			return 0;
		}
		
		int t_t_len = ntohll(t_len);

		m_nalu.len = t_t_len;
		if (1 != fread(m_nalu.buf, t_t_len, 1, bits))
		{
			return 0;
		}

		return m_nalu.len;
	}
	int pos = 0;
	int StartCodeFound, rewind;

	m_nalu.startcodeprefix_len = 3;//初始化码流序列的开始字符为3个字节

	if (3 != fread(Buf, 1, 3, bits))//从码流中读3个字节
	{

		return 0;
	}
	info2 = FindStartCode2(Buf);//判断是否为0x000001 
	if (info2 != 1)
	{
		//如果不是，再读一个字节
		if (1 != fread(Buf + 3, 1, 1, bits))//读一个字节
		{
			return 0;
		}
		info3 = FindStartCode3(Buf);//判断是否为0x00000001
		if (info3 != 1)//如果不是，返回-1
		{
			return -1;
		}
		else
		{
			//如果是0x00000001,得到开始前缀为4个字节
			pos = 4;
			m_nalu.startcodeprefix_len = 4;
		}
	}
	else
	{
		//如果是0x000001,得到开始前缀为3个字节
		m_nalu.startcodeprefix_len = 3;
		pos = 3;
	}
	//查找下一个开始字符的标志位
	StartCodeFound = 0;
	info2 = 0;
	info3 = 0;

	while (!StartCodeFound)
	{
		if (feof(bits))//判断是否到了文件尾
		{
			m_nalu.len = (pos - 1) - m_nalu.startcodeprefix_len;

			memcpy(&m_nalu.buf[4], &Buf[m_nalu.startcodeprefix_len], m_nalu.len);

			m_nalu.forbidden_bit = m_nalu.buf[4] & 0x80; //1 bit
			m_nalu.nal_reference_idc = m_nalu.buf[4] & 0x60; // 2 bit
			m_nalu.nal_unit_type = (m_nalu.buf[4]) & 0x1f;// 5 bit

			if (flags == 1)
			{
				m_nalu.nal_unit_type = (m_nalu.buf[4] & 0x7E) >> 1;

				m_nalu.Tid = (m_nalu.buf[5] & 0x07);

				char temp = (m_nalu.buf[5] & 0xF8) >> 3;

				char temp1 = (m_nalu.buf[4] & 0x01) << 6;

				m_nalu.LayerId = temp | temp1;
			}
			

		

			m_nalu.buf[0] = 0x00;
			m_nalu.buf[1] = 0x00;
			m_nalu.buf[2] = 0x00;
			m_nalu.buf[3] = 0x01;

			m_nalu.len += 4;
			return m_nalu.len;

		}
		Buf[pos++] = fgetc(bits);//读一个字节到BUF中
		info3 = FindStartCode3(&Buf[pos - 4]);//判断是否为0x00000001
		if (info3 != 1)
			info2 = FindStartCode2(&Buf[pos - 3]);//判断是否为0x000001
		StartCodeFound = (info2 == 1 || info3 == 1);
	}

	// Here, we have found another start code (and read length of startcode bytes more than we should
	// have.  Hence, go back in the file
	rewind = (info3 == 1) ? -4 : -3;

	if (0 != fseek(bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾
	{
		printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
	}

	// Here the Start code, the complete NALU, and the next start code is in the Buf.  
	// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
	// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code


	m_nalu.len = (pos + rewind) - m_nalu.startcodeprefix_len;
	//m_nalu.buf = std::make_shared<char>(m_nalu.len);
	memcpy(&m_nalu.buf[4], &Buf[m_nalu.startcodeprefix_len], m_nalu.len);//拷贝一个完整NALU，不拷贝起始前缀0x000001或0x00000001
	m_nalu.forbidden_bit = m_nalu.buf[4] & 0x80;		//1 bit
	m_nalu.nal_reference_idc = m_nalu.buf[4] & 0x60;	//2 bit
	m_nalu.nal_unit_type = (m_nalu.buf[4]) & 0x1f;	//5 bit

	if (flags == 1)
	{
		m_nalu.nal_unit_type = (m_nalu.buf[4] & 0x7E) >> 1;

		m_nalu.Tid = (m_nalu.buf[5] & 0x07);

		char temp = (m_nalu.buf[5] & 0xF8) >> 3;

		char temp1 = (m_nalu.buf[4] & 0x01) << 6;

		m_nalu.LayerId = temp | temp1;
	}


	m_nalu.buf[0] = 0x00;
	m_nalu.buf[1] = 0x00;
	m_nalu.buf[2] = 0x00;
	m_nalu.buf[3] = 0x01;

	m_nalu.len += 4;


	return m_nalu.len;
}


int ParseH264::GetAnnexbCompositeNALU(int flags, char*& p, int& len, bool& isKey, int mutBand)
{

	m_buffer.clear();
	
	NALU_t* t_Nalu = NULL;
	int ret = 0;
	int iCount = 0;
	do 
	{
		ret = GetAnnexbNALU(t_Nalu, flags);

		if (0 == flags)
		{
			//printf("##############************** t_nalu.len:%d \n", t_Nalu->len);
			m_buffer.insert(m_buffer.end(), t_Nalu->buf, t_Nalu->buf + t_Nalu->len);
			if (7 == t_Nalu->nal_unit_type || 8 == t_Nalu->nal_unit_type || 6 == t_Nalu->nal_unit_type)
			{
				continue;
			}
			if (5 == t_Nalu->nal_unit_type)
			{
				isKey = true;
				iCount++;
				if (iCount < mutBand)
				{
					continue;
				}
				iCount = 0;
			}
			else
			{
				isKey = false;
				iCount++;
				if (iCount < mutBand)
				{
					continue;
				}
				iCount = 0;
			}
			break;
		}
		else if (1 == flags)
		{
			m_buffer.insert(m_buffer.end(), t_Nalu->buf, t_Nalu->buf + t_Nalu->len);
			if (32 == t_Nalu->nal_unit_type || 33 == t_Nalu->nal_unit_type || 34 == t_Nalu->nal_unit_type)
			{
				continue;
			}
			if (19 == t_Nalu->nal_unit_type)
			{
				isKey = true;
				iCount++;
				if (iCount < mutBand)
				{
					continue;
				}
				iCount = 0;
			}
			else
			{
				isKey = false;
				iCount++;
				if (iCount < mutBand)
				{
					continue;
				}
				iCount = 0;
			}
			break;
		}
		else if (2 == flags)
		{
			m_buffer.insert(m_buffer.end(), t_Nalu->buf, t_Nalu->buf + t_Nalu->len);
			if (19 == t_Nalu->bFrameType)
			{
				isKey = true;

			}
			else
			{
				isKey = false;

			}
		}

	} while (1);

	p = (char *)m_buffer.data();
	len = m_buffer.size();
	return ret;
}

